import { AxiosRequestConfig } from 'axios'
import qs from 'qs'

import type { IRes } from '@/axiosConfig/utils'
import { axiosMock } from '@axiosMock' // 必须使用别名

/** 随机取数组成员 --- 仅限 `__mock__` 中使用 */
const randArrItem = <T, NP extends 0 | 0.1 | 0.2 | 0.3 | 0.4 | 0.5 | 0.6 | 0.7 | 0.8 | 0.9 = 0>(
  arr: readonly T[],
  nullProbability?: NP,
): NP extends 0 ? T : T | null => {
  const np = nullProbability ?? 0
  if (np && Math.random() < np) return null as T
  return arr[Math.floor(Math.random() * arr.length)]
}

/** 自定义响应延时 & 控制台输出信息 --- 仅限 `__mock__` 中使用 */
const delayFn = <T>(
  delay: number,
  resFn: (parsedConfig: AxiosRequestConfig) => IRes<T>,
): ((config: AxiosRequestConfig) => Promise<[200, IRes<T>]>) => {
  return config => {
    const parsedConfig = { ...config }
    if (config.data && typeof config.data === 'string') {
      try {
        parsedConfig.data = JSON.parse(config.data)
      } catch {
        parsedConfig.data = qs.parse(config.data)
      }
    }
    const { method, url, params, data, responseType, signal, cancelToken } = parsedConfig

    const log = (fn: () => void) => {
      console.group(`${method}::${url}`)
      if (params) console.log('params:', params)
      if (data) console.log('data:', data)
      fn()
      console.log('info:', { delay, parsedConfig, config })
      console.groupEnd()
    }

    return new Promise<[200, IRes<T>]>((resolve, reject) => {
      const timer = setTimeout(() => {
        let res = resFn(parsedConfig)
        if (responseType === 'blob' && typeof res === 'string') {
          res = new Blob([res]) as unknown as IRes<T>
        }
        resolve([200, res])
        log(() => console.log('$res:', res))
      }, delay)

      signal?.addEventListener?.('abort', (e: any) => {
        reject(e.target.reason)
        clearTimeout(timer)
      })
      cancelToken?.promise.then(reason => {
        reject(reason)
        clearTimeout(timer)
      })
    }).catch(err => {
      log(() => console.error('err:', `${err}`))
      throw err
    })
  }
}

export { randArrItem, delayFn, axiosMock }
